#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>

#include "stm32f4xx.h"

/*
Table 1. Selected SD Memory Card Commands
Command    Mnemonic             Argument Reply  Description
0 (0x00)   GO_IDLE_STATE        none     R1     Resets the SD card.
9 (0x09)   SEND_CSD             none     R1     Sends card-specific data.
10 (0x0a)  SEND_CID             none     R1     Sends card identification.
17 (0x11)  READ_SINGLE_BLOCK    address  R1     Reads a block at byte address.
24 (0x18)  WRITE_BLOCK          address  R1     Writes a block at byte address.
55 (0x37)  APP_CMD              none     R1     Prefix for application command.
59 (0x3b)  CRC_ON_OFF           Only Bit 0 R1   Argument sets CRC on (1) or off (0).
41 (0x29)  SEND_OP_COND         none     R1     Starts card initialization.
*/

/****************/
static u8 Encode(u8 Seed, u8 Input , u8 Depth)
/* --
                  Produce a 7 bit CRC value Msb first.
                 Seed is last round or initial round shift register
                   value (lower 7 bits significant).
                 Input is an 8 bit value from byte stream being CRCd.
                 CRC register is seeded initially with the value 0 prior
                  to mixing in the variable packet data.
                 Depth is usually 8, but the last time is 7 to shift in
                   the augment string of 7 zeros.
*****************/
{
    register u8 regval;      // shift register byte.
    register u8 count;
    register u8 cc;          // data to manipulate.
#define POLYNOM (0x9)        // polynomical value to XOR when 1 pops out.

    /*BODY*/

    regval = Seed;    // get prior round's register value.
    cc = Input;       // get input byte to generate CRC, MSB first.

    /* msb first of byte for Depth elements */
    for ( count = Depth     // set count to 8 or 7.
          ; count--        // for count # of bits.
          ;  cc <<= 1     // shift input value towards MSB to get next bit.
          )
    {
        // Shift seven bit register left and put in MSB value of input to LSB.
        regval = (regval << 1) + ( (cc & 0x80) ? 1 : 0 );
        // Test D7 of shift register as MSB of byte, test if 1 and therefore XOR.
        if (regval & 0x80)
            regval ^= POLYNOM;
    } // end byte loop.
    return (regval & 0x7f);    // return lower 7 bits of CRC as value to use.
}


u8 CalCRC7(u8 cmd, u32 arg)
{
    u8 val;     // pointer into command line argument list.
    u8 CrcAccum; // local storage of each round of CRC.

    CrcAccum = 0;

    // loop through 5 command line decimal values. Display in HEX to
    //  stdout, can be captured via >> on cmdline.
    CrcAccum = Encode(CrcAccum, cmd, 8);
    CrcAccum = Encode(CrcAccum, (u8)(arg >> 24), 8);
    CrcAccum = Encode(CrcAccum, (u8)(arg >> 16), 8);
    CrcAccum = Encode(CrcAccum, (u8)(arg >> 8), 8);
    CrcAccum = Encode(CrcAccum, (u8)arg, 8);

    // mix in last 7 bits of 0s to augment, and then shift final CRC
    //  remainder left and OR in fixed 1 LSB.
    val = Encode(CrcAccum, 0, 7 );
    val = (val << 1) + 1;

    return val;
}


/* end of file */

